package qc.module.qms.service.alarm;

import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import qc.common.core.constants.QmsConstant;
import qc.common.core.enums.qms.*;
import qc.module.qms.dto.alarm.QmsPointDataValueAlarmJudgeResultDto;
import qc.module.qms.dto.alarm.QmsPointDataValueAlarmRuleJudgeResultDto;
import qc.module.qms.dto.pointdata.QmsPointNumericDataDto;
import qc.module.qms.entity.QmsAlarmDataPoint;
import qc.module.qms.entity.QmsAlarmDataRule;
import qc.module.qms.service.QmsBasicConfigCacheGetService;

import java.time.LocalDateTime;
import java.util.LinkedList;
import java.util.List;

/**
 * 点号数据值告警判定Service，数据值不合理判定及防误处理判定Service，仅进行判定出结果，不生成告警记录也不修改数据值
 *
 * @author QuCheng Tech
 * @since 2025/10/18
 */
@Service
public class QmsPointDataValueAlarmJudgeService {
    private static final Logger logger = LoggerFactory.getLogger(QmsPointDataValueAlarmJudgeService.class);

    @Autowired
    private QmsBasicConfigCacheGetService basicConfigCacheGetService;

    /**
     * 对指定的一条点号数据进行告警判定和防误处理，同时进行告警判定和防误处理
     * 用于在点号数据保存时（未操作数据库之前）对需要进行防误处理的告警规则先进行判定，对防误处理需要修改的数据值进行重新赋值
     * 在人工对点号数据质量进行设置时也进行告警判定及防误处理，该情况下均为人工操作，判断后如触发防误处理会返回到前端进行提示，不会自动对数据值进行修改
     *
     * @param pointid 点号编码
     * @param tmseg   点号时段类型
     * @param optype  流程节点操作类型，需要根据操作类型确定是使用点号数据中的数据质量还是根据操作确定设置后的数据质量
     * @param data    点号数据，数据质量必须保持与新增或修改后数据库中的数据质量一致
     * @return qc.module.qms.dto.alarm.QmsPointDataValueAlarmJudgeResultDto
     * @author QuCheng Tech
     * @since 2025/10/21
     */
    public QmsPointDataValueAlarmJudgeResultDto judgeErrorProof(String pointid, QmsPointTimeSegmentEnum tmseg, QmsDataFlowOperateTypeEnum optype, QmsPointNumericDataDto data) {
        //只判定告警规则中有数据值防误处理的规则
        return judge(pointid, tmseg, optype, data, true);
    }

    /**
     * 对指定的一条点号数据进行告警判定，只进行告警判定，不进行防误处理
     * 用于在点号数据保存后通过点号数据消息触发告警
     *
     * @param pointid 点号编码
     * @param tmseg   点号时段类型
     * @param optype  流程节点操作类型，需要根据操作类型确定是使用点号数据中的数据质量还是根据操作确定设置后的数据质量
     * @param data    点号数据，数据质量必须保持与新增或修改后数据库中的数据质量一致
     * @return qc.module.qms.dto.alarm.QmsPointDataValueAlarmJudgeResultDto
     * @author QuCheng Tech
     * @since 2025/10/21
     */
    public QmsPointDataValueAlarmJudgeResultDto judgeAlarm(String pointid, QmsPointTimeSegmentEnum tmseg, QmsDataFlowOperateTypeEnum optype, QmsPointNumericDataDto data) {
        //只判定告警规则中有数据值防误处理的规则
        return judge(pointid, tmseg, optype, data, false);
    }

    /**
     * 对指定的一条点号数据（不管数据质量，即在任意一条数据值或数据质量变化时均需要进行告警判定）进行告警判定，根据系统中的所有有效告警规则进行告警判定和防误处理
     * 分别提供2个方法，包含防误处理的告警需要在QmsPointDataManageService中被调用，不包含防误处理的由点号数据消息的告警处理消费者处理中被调用
     * 只有保存点号数据才触发告警和防误处理，修改数据质量通过点号数据消息触发（不在修改数据质量的同时进行判断和处理）
     *
     * @param pointid    点号编码
     * @param tmseg      点号时段类型
     * @param optype     流程节点操作类型，需要根据操作类型确定是使用点号数据中的数据质量还是根据操作确定设置后的数据质量
     * @param data       点号数据，数据质量必须保持与新增或修改后数据库中的数据质量一致
     * @param errorProof 是否需要进行防误处理
     * @return qc.module.qms.dto.alarm.QmsPointDataValueAlarmJudgeResultDto
     * @author QuCheng Tech
     * @since 2025/10/21
     */
    public QmsPointDataValueAlarmJudgeResultDto judge(String pointid, QmsPointTimeSegmentEnum tmseg, QmsDataFlowOperateTypeEnum optype, QmsPointNumericDataDto data, boolean errorProof) {
        //基本条件判断，如果输入不合理不触发任何告警；初始化判定结果为不触发任何告警
        QmsPointDataValueAlarmJudgeResultDto result = new QmsPointDataValueAlarmJudgeResultDto();
        result.setAlarmRuleCount(0x0);
        result.setHasTriggerAlarm(false);
        result.setTriggerAlarmRuleCount(0x0);
        result.setHasTriggerErrorProof(false);
        result.setTriggerErrorProofRuleCount(0x0);
        result.setErrorMsg(null);
        result.setRuleJudgeResults(null);

        //输入错误提示信息
        String inputErrorMsg = null;
        if (StringUtils.isBlank(pointid))
            inputErrorMsg += "点号编码不能为空，";
        if (tmseg == null)
            inputErrorMsg += "点号时段类型不能为空，";
        else if (tmseg == QmsPointTimeSegmentEnum.UN_DEFINE)
            inputErrorMsg += "点号时段类型错误，";
        if (data == null)
            inputErrorMsg += "点号数据不能为空，";
        else if (data.getTm() == null)
            inputErrorMsg += "点号数据时标不能为空，";

        //如果输入条件错误，不需要进行判定，直接返回结果
        if (StringUtils.isNotBlank(inputErrorMsg)) {
            result.setErrorMsg(inputErrorMsg);

            return result;
        }

        LocalDateTime datatime = data.getTm();
        //需要根据当前的点号数据质量标记判断，如果数据是有效数据进行判断是否产生新告警；如果是设置数据质量标记为无效数据判断是否有已有告警是否需要进行取消或关闭
        //数据质量需要根据操作类型optype分别进行赋值，如果optype是保存点号数据使用data中的数据质量，如果optype是人工设置数据质量则根据optype对数据质量赋值（不使用data中的数据质量）
        QmsPointDataQualityEnum afterOperateDataQuality = data.getQuality();//在进行数据保存或数据质量设置后的点号数据质量
        if (optype == QmsDataFlowOperateTypeEnum.DELETE_POINT_DATA)
            afterOperateDataQuality = QmsPointDataQualityEnum.DELETE;
        else if (optype == QmsDataFlowOperateTypeEnum.SET_POINT_DATA_IS_ERROR)
            afterOperateDataQuality = QmsPointDataQualityEnum.ERROR;
        else if (optype == QmsDataFlowOperateTypeEnum.SET_POINT_DATA_IS_RIGHT)
            afterOperateDataQuality = QmsPointDataQualityEnum.MANUAL;
        if (afterOperateDataQuality.getIndex() < QmsConstant.POINT_DATA_VALID_QUALITY_FROM.getIndex()) {
            //在设置数据质量标记时，关闭或取消已有告警  closeOrCancelExistAlarm 判断当前数据时标的时间点
            //// TODO: 2025/10/22 获取当前点号和数据时标的未关闭取消的告警记录，是否需要对告警记录进行关闭？？ 
        } else {
            //一个点号数据可能会有多条告警规则，可能有的告警规则只是进行告警，有的告警规则会需要进行防误处理（修改数据值）
            List<QmsAlarmDataRule> alarmRules = null;
            //根据传入标识判定是否需要进行防误处理，还是只需要判定告警
            if (errorProof == true)
                alarmRules = basicConfigCacheGetService.getValidErrorProofPointDataAlarmRules(pointid, tmseg, datatime);
            else
                alarmRules = basicConfigCacheGetService.getValidNoErrorProofPointDataAlarmRules(pointid, tmseg, datatime);

            if (alarmRules != null && alarmRules.size() > 0x0) {
                //初始化所有有效告警规则判定的汇总结果
                int alarmRuleCount = 0x0;
                boolean hasTriggerAlarm = false;
                int triggerAlarmRuleCount = 0x0;
                boolean hasTriggerErrorProof = false;
                int triggerErrorProofRuleCount = 0x0;
                List<QmsPointDataValueAlarmRuleJudgeResultDto> ruleJudgeResults = new LinkedList<>();
                //针对当前点号将所有有效告警规则全部判断一遍，不触发告警是不触发任意一条告警，触发告警同时触发所有有效告警规则
                for (QmsAlarmDataRule alarmRule : alarmRules) {
                    //先根据点号数据值、时段初值、时段末值字段判分别断是否有对应告警规则，再判断告警规则中是否有防误处理及规则是否有效
                    List<QmsAlarmDataPoint> alarmDataPointRelations = basicConfigCacheGetService.getAlarmRulePointRelations(alarmRule.getRuleid(), true);
                    if (alarmDataPointRelations != null && alarmDataPointRelations.size() > 0x0) {
                        for (QmsAlarmDataPoint relation : alarmDataPointRelations) {
                            //根据告警规则与点号关联中的数据值字段取对应的数据值
                            //先初始化获取对应数据值字段的数据值为NaN，获取不到对应的字段数据值时不进行判断
                            Double dataValue = Double.NaN;
                            QmsPointValueFieldEnum valuefield = relation.getValuefield();
                            //如果指定的数据值字段错误不进行判断，根据获取对应字段的数据值是否为NaN进行判定
                            if (valuefield == QmsPointValueFieldEnum.VALUE)
                                dataValue = data.getV();
                            else if (valuefield == QmsPointValueFieldEnum.BEGIN_VALUE)
                                dataValue = data.getBeginv();
                            else if (valuefield == QmsPointValueFieldEnum.END_VALUE)
                                dataValue = data.getEndv();
                            if (dataValue != null && Double.isNaN(dataValue) == false) {
                                QmsPointDataValueAlarmRuleJudgeResultDto rulePointRelationJudgeResult = this.judgeRule(pointid, tmseg, datatime, dataValue.doubleValue(), valuefield, errorProof, alarmRule);
                                //判断当前告警规则关联点号的判定结果
                                if (rulePointRelationJudgeResult != null) {
                                    ruleJudgeResults.add(rulePointRelationJudgeResult);
                                    //如果一条告警规则判定时出现了错误，输入信息错误不作为判定返回结果
                                    if (StringUtils.isNotBlank(rulePointRelationJudgeResult.getErrorMsg())) {

                                    } else {
                                        //告警规则判定成功，获取判断的结果是否触发告警和是否触发防误处理
                                        alarmRuleCount++;
                                        //判断是否有触发告警
                                        if (rulePointRelationJudgeResult.isHasTriggerAlarm()) {
                                            //有触发告警，可能是等级告警或复归/平安报告警
                                            hasTriggerAlarm = true;
                                            triggerAlarmRuleCount++;
                                            //判断是否有触发防误处理
                                            if (rulePointRelationJudgeResult.isHasTriggerErrorProof()) {
                                                hasTriggerErrorProof = true;
                                                triggerErrorProofRuleCount++;
                                            }
                                        }
                                    }
                                }
                            }
                        }
                    }
                }

                //对返回结果赋值
                result.setAlarmRuleCount(alarmRuleCount);
                result.setHasTriggerAlarm(hasTriggerAlarm);
                result.setTriggerAlarmRuleCount(triggerAlarmRuleCount);
                result.setHasTriggerErrorProof(hasTriggerErrorProof);
                result.setTriggerErrorProofRuleCount(triggerErrorProofRuleCount);
                result.setRuleJudgeResults(ruleJudgeResults);
            }
        }

        return result;
    }

    /**
     * 判断指定字段的数据值和指定的一条规则（规则不验证是否有效，此方法可以用于人工对规则进行验证使用），使用此方法传入的数据值均认为是有效数据
     * 此方法要对产生告警或取消告警（复归、平安报）进行判定，根据返回结果中的告警等级确定是触发哪个等级的告警或者是触发取消告警
     *
     * @param pointid    点号编码
     * @param tmseg      点号时段类型
     * @param dataTime   数据时标
     * @param dataValue  数据值，默认传入的数据质量均为有效数据
     * @param valuefield 数据值字段，可能需要提取其他数据进行判断，指定提取相同点号数据时的数据值字段
     * @param errorProof 是否需要进行防误处理
     * @param rule       指定进行告警判定的规则，不管告警规则是否有效（是否为启用状态）也不管数据时标是否在告警规则的生效时间段内
     * @return qc.module.qms.dto.alarm.QmsPointDataValueAlarmRuleJudgeResultDto
     * @author QuCheng Tech
     * @since 2025/10/21
     */
    public QmsPointDataValueAlarmRuleJudgeResultDto judgeRule(String pointid, QmsPointTimeSegmentEnum tmseg, LocalDateTime dataTime, double dataValue,
                                                              QmsPointValueFieldEnum valuefield, boolean errorProof, QmsAlarmDataRule rule) {
        //如果传入的数据值字段无效，默认使用value字段；数据值字段只能是value、beginv或endv
        if (valuefield != QmsPointValueFieldEnum.VALUE && valuefield != QmsPointValueFieldEnum.BEGIN_VALUE && valuefield != QmsPointValueFieldEnum.END_VALUE)
            valuefield = QmsPointValueFieldEnum.VALUE;

        //基本条件判断，如果输入不合理不触发任何告警；初始化判定结果为不触发任何告警
        QmsPointDataValueAlarmRuleJudgeResultDto result = new QmsPointDataValueAlarmRuleJudgeResultDto();
        result.setHasTriggerAlarm(false);
        result.setAlarmLevel(QmsAlarmLevelEnum.NONE);
        result.setHasTriggerErrorProof(false);
        result.setTriggerErrorProofValueField(valuefield);
        result.setErrorProofRawDataValue(dataValue);
        result.setErrorProofSetDataValue(Double.NaN);

        //输入错误提示信息
        String inputErrorMsg = null;
        //点号ID、时段类型、数据时标可以没有，只有在判断数据值突变等规则需要获取前面时间数据时才需要使用
        if (Double.isNaN(dataValue) || Double.isInfinite(dataValue))
            inputErrorMsg = "要判定的数据值无效，不能是NaN或无穷大";
        //数据值字段可以为空或传入错误，默认使用value字段，数据值字段可以为空，如果不需要获取前面时间数据则不需要数据值字段
        //告警规则必须有，不判断是否有效（是否需要传入参数指示是否要对传入的规则有效性进行验证）？？
        if (rule == null) {
            inputErrorMsg = "要进行判定的告警规则不能为空";
        } else {
            //判断告警规则中的判定方法枚举是否正确
            //4个等级的告警值不能全部为null，如果4个等级的告警值全部为null不会产生预警也就不会产生取消/复归/平安报（即使设置了触发取消告警为true也无效）
            if (rule.getMethod() == QmsDataValueAlarmJudgeMethodEnum.UN_DEFINE)
                inputErrorMsg = "要进行判定的告警规则不能为空";
            else if (StringUtils.isBlank(rule.getAlarmvalue1()) && StringUtils.isBlank(rule.getAlarmvalue2())
                    && StringUtils.isBlank(rule.getAlarmvalue3()) && StringUtils.isBlank(rule.getAlarmvalue4()))
                inputErrorMsg = "要进行判定的告警规则4个等级的告警值均未设置";
        }
        //如果输入信息验证失败，直接返回提示错误信息结果
        if (StringUtils.isNotBlank(inputErrorMsg)) {
            result.setErrorMsg(inputErrorMsg);

            return result;
        }

        //指定的告警规则不为null时，不管规则ID和名称是否为空，也不管规则的有效性
        result.setAlarmRuleId(rule.getRuleid());
        result.setAlarmRuleName(rule.getRulename());
        // 告警等级由高到低逐个进行判定，如果均不触发判定是否触发复归/平安报
        //判断触发告警需要在同一个方法中一次判断完成（包含触发复归/平安报），如果分为不同的调用会存在重复提取相同数据的情况
        //是统一一个方法进行告警判定数据的提取，还是在每个判定方法中分别实现数据提取方法
        //每种判定方法有自己的判定规则和需要用到的数据，由各判定方法自行提取数据
        QmsPointDataValueAlarmRuleJudgeResultDto judgeAlarmValueResult = null;
        switch (rule.getMethod()) {
            case VALUE_OUT_OF_LIMIT:
                judgeAlarmValueResult = this.judgeValueOutOfLimitAlarm(pointid, tmseg, dataTime, dataValue, errorProof, rule.getAlarmcontent(),
                        rule.getAlarmvalue1(), rule.getAlarmvalue2(), rule.getAlarmvalue3(), rule.getAlarmvalue4(), rule.getTriggercancel());
                break;
            case FLUCTUATION_OUT_OF_LIMIT:
                judgeAlarmValueResult = this.judgeFluctuationOutOfLimitAlarm(pointid, tmseg, dataTime, dataValue, errorProof, valuefield, rule.getDataconfig(),
                        rule.getAlarmcontent(), rule.getAlarmvalue1(), rule.getAlarmvalue2(), rule.getAlarmvalue3(), rule.getAlarmvalue4(), rule.getTriggercancel());
                break;
            case VALUE_NOT_EQUAL:
                judgeAlarmValueResult = this.judgeValueNotEqualAlarm(pointid, tmseg, dataTime, dataValue, errorProof, valuefield, rule.getDataconfig(),
                        rule.getAlarmcontent(), rule.getAlarmvalue1(), rule.getAlarmvalue2(), rule.getAlarmvalue3(), rule.getAlarmvalue4(), rule.getTriggercancel());
                break;
            case VALUE_ALL_EQUAL:
                judgeAlarmValueResult = this.judgeValueAllEqualAlarm(pointid, tmseg, dataTime, dataValue, errorProof, valuefield, rule.getDataconfig(),
                        rule.getAlarmcontent(), rule.getAlarmvalue1(), rule.getAlarmvalue2(), rule.getAlarmvalue3(), rule.getAlarmvalue4(), rule.getTriggercancel());
                break;
            case NON_ZERO:
                judgeAlarmValueResult = this.judgeValueNonZeroAlarm(pointid, tmseg, dataTime, dataValue, errorProof, valuefield, rule.getDataconfig(),
                        rule.getAlarmcontent(), rule.getAlarmvalue1(), rule.getAlarmvalue2(), rule.getAlarmvalue3(), rule.getAlarmvalue4(), rule.getTriggercancel());
                break;
            case TRENDENCY_NOT_SAME:
                judgeAlarmValueResult = this.judgeTrendencyNotSameAlarm(pointid, tmseg, dataTime, dataValue, errorProof, valuefield, rule.getDataconfig(),
                        rule.getAlarmcontent(), rule.getAlarmvalue1(), rule.getAlarmvalue2(), rule.getAlarmvalue3(), rule.getAlarmvalue4(), rule.getTriggercancel());
                break;
            case RESERVOIR_WATER_ERROR:
                judgeAlarmValueResult = this.judgeReservoirWaterErrorAlarm(pointid, tmseg, dataTime, dataValue, errorProof, valuefield, rule.getDataconfig(),
                        rule.getAlarmcontent(), rule.getAlarmvalue1(), rule.getAlarmvalue2(), rule.getAlarmvalue3(), rule.getAlarmvalue4(), rule.getTriggercancel());
                break;
            default:
                break;
        }

        if (judgeAlarmValueResult != null && judgeAlarmValueResult.isHasTriggerAlarm() == true) {
            //如果判定触发了告警，将判定的告警结果赋值给返回对象
            result.setHasTriggerAlarm(true);
            //告警消息的内容，在此处根据是否是演习添加前缀？？还是在调用方进行判断后添加？？
            result.setAlarmMsg(judgeAlarmValueResult.getAlarmMsg());
            result.setHasTriggerErrorProof(judgeAlarmValueResult.isHasTriggerErrorProof());
            result.setTriggerErrorProofValueField(valuefield);//如果触发防误处理，赋值的数据值字段就是用于判定是否触发告警的数据值字段
            result.setErrorProofRawDataValue(judgeAlarmValueResult.getErrorProofRawDataValue());
            result.setErrorProofSetDataValue(judgeAlarmValueResult.getErrorProofSetDataValue());
            result.setErrorProofSetMsg(judgeAlarmValueResult.getErrorProofSetMsg());
        }

        //所有告警等级和取消告警均不触发，返回初始化的判定结果
        return result;
    }

    /**
     * 数值超限告警判定方法，不需要提取其他数据
     *
     * @param pointid            点号编码
     * @param tmseg              点号时段类型
     * @param dataTime           数据时标
     * @param dataValue          数据值
     * @param errorProof         是否需要进行防误处理
     * @param alarmContent       告警信息内容模板
     * @param redAlarmValue      红色告警值，可以为null，无效时不进行判定
     * @param orangeAlarmValue   橙色告警值，可以为null，无效时不进行判定
     * @param yellowAlarmValue   黄色告警值，可以为null，无效时不进行判定
     * @param blueAlarmValue     蓝色告警值，可以为null，无效时不进行判定
     * @param triggerCancelAlarm 是否触发取消/复归/平安报告警
     * @return qc.module.qms.dto.alarm.QmsPointDataValueAlarmRuleJudgeResultDto
     * @author QuCheng Tech
     * @since 2025/10/21
     */
    public QmsPointDataValueAlarmRuleJudgeResultDto judgeValueOutOfLimitAlarm(String pointid, QmsPointTimeSegmentEnum tmseg, LocalDateTime dataTime, double dataValue, boolean errorProof, String alarmContent,
                                                                              String redAlarmValue, String orangeAlarmValue, String yellowAlarmValue, String blueAlarmValue, boolean triggerCancelAlarm) {
        //基本条件判断，如果输入不合理不触发任何告警；初始化判定结果为不触发任何告警
        QmsPointDataValueAlarmRuleJudgeResultDto result = new QmsPointDataValueAlarmRuleJudgeResultDto();
        result.setHasTriggerAlarm(false);
        result.setAlarmLevel(QmsAlarmLevelEnum.NONE);
        result.setHasTriggerErrorProof(false);
        result.setErrorProofRawDataValue(dataValue);
        result.setErrorProofSetDataValue(Double.NaN);

        //如果本次的数据值为NaN或无穷大无法进行判定
        if (Double.isNaN(dataValue) == false && Double.isInfinite(dataValue) == false) {
            //测试模拟使用
            double maxValue = 872.9;
            double amendMaxValue = 872.88;
            if (dataValue > maxValue) {
                result.setHasTriggerAlarm(true);
                result.setAlarmMsg("");
                result.setAlarmLevel(QmsAlarmLevelEnum.BLUE);
                result.setAlarmStatus(QmsAlarmStatusEnum.NEW);
                if (errorProof == true) {
                    result.setHasTriggerErrorProof(true);
                    result.setTriggerErrorProofValueField(QmsPointValueFieldEnum.VALUE);
                    result.setErrorProofRawDataValue(dataValue);
                    result.setErrorProofSetDataValue(amendMaxValue);
                    result.setErrorProofSetMsg("数据值[" + dataValue + "]超过[" + maxValue + "]，自动修订为[" + amendMaxValue + "]");
                }

                return result;
            }

            //记录逐个告警等级的判定结果，默认为不触发告警
            QmsAlarmLevelEnum triggerAlarmLevel = QmsAlarmLevelEnum.NONE;
            if (StringUtils.isNotBlank(redAlarmValue)) {
                //判断红色等级是否触发
                //如果触发了红色等级的告警，直接返回红色等级告警判定结果
                return result;
            }
            if (triggerAlarmLevel == QmsAlarmLevelEnum.NONE && StringUtils.isNotBlank(orangeAlarmValue)) {
                //判断橙色等级是否触发
                //如果触发了橙色等级的告警，直接返回橙色等级告警判定结果
                return result;
            }
            if (triggerAlarmLevel == QmsAlarmLevelEnum.NONE && StringUtils.isNotBlank(yellowAlarmValue)) {
                //判断黄色等级是否触发
                //如果触发了黄色等级的告警，直接返回黄色等级告警判定结果
                return result;
            }
            if (triggerAlarmLevel == QmsAlarmLevelEnum.NONE && StringUtils.isNotBlank(blueAlarmValue)) {
                //判断蓝色等级是否触发
                //如果触发了蓝色等级的告警，直接返回蓝色等级告警判定结果
                return result;
            }
            if (triggerAlarmLevel == QmsAlarmLevelEnum.NONE && triggerCancelAlarm == true) {
                //判断复归/平安是否触发，要求规则中设置的取消告警标记为true
                //如果触发了取消告警，直接返回取消告警判定结果
                return result;
            }
        }

        return result;
    }

    /**
     * 数据变幅超限告警判定方法，需要提取同点号的时间往前的数据
     *
     * @param pointid            点号编码
     * @param tmseg              点号时段类型
     * @param dataTime           数据时标
     * @param dataValue          数据值
     * @param errorProof         是否需要进行防误处理
     * @param valuefield         数据值字段
     * @param getDataConfig      判定提取数据配置
     * @param alarmContent       告警信息内容模板
     * @param redAlarmValue      红色告警值，可以为null，无效时不进行判定
     * @param orangeAlarmValue   橙色告警值，可以为null，无效时不进行判定
     * @param yellowAlarmValue   黄色告警值，可以为null，无效时不进行判定
     * @param blueAlarmValue     蓝色告警值，可以为null，无效时不进行判定
     * @param triggerCancelAlarm 是否触发取消/复归/平安报告警
     * @return qc.module.qms.dto.alarm.QmsPointDataValueAlarmRuleJudgeResultDto
     * @author QuCheng Tech
     * @since 2025/10/21
     */
    QmsPointDataValueAlarmRuleJudgeResultDto judgeFluctuationOutOfLimitAlarm(String pointid, QmsPointTimeSegmentEnum tmseg, LocalDateTime dataTime, double dataValue, boolean errorProof,
                                                                             QmsPointValueFieldEnum valuefield, String getDataConfig, String alarmContent,
                                                                             String redAlarmValue, String orangeAlarmValue, String yellowAlarmValue, String blueAlarmValue, boolean triggerCancelAlarm) {
        //基本条件判断，如果输入不合理不触发任何告警；初始化判定结果为不触发任何告警
        QmsPointDataValueAlarmRuleJudgeResultDto result = new QmsPointDataValueAlarmRuleJudgeResultDto();
        result.setHasTriggerAlarm(false);
        result.setAlarmLevel(QmsAlarmLevelEnum.NONE);
        result.setHasTriggerErrorProof(false);
        result.setErrorProofRawDataValue(dataValue);
        result.setErrorProofSetDataValue(Double.NaN);

        //在告警方法未实现前，设置错误提示信息标识该告警判断方法未实现
        result.setErrorMsg("数据变幅超限告警判定方法暂时未实现，不能进行告警判定");

        //如果本次的数据值为NaN或无穷大无法进行判定
        if (Double.isNaN(dataValue) == false && Double.isInfinite(dataValue) == false) {
            //记录逐个告警等级的判定结果，默认为不触发告警
            QmsAlarmLevelEnum triggerAlarmLevel = QmsAlarmLevelEnum.NONE;
            if (StringUtils.isNotBlank(redAlarmValue)) {
                //判断红色等级是否触发
                //如果触发了红色等级的告警，直接返回红色等级告警判定结果
                return result;
            }
            if (triggerAlarmLevel == QmsAlarmLevelEnum.NONE && StringUtils.isNotBlank(orangeAlarmValue)) {
                //判断橙色等级是否触发
                //如果触发了橙色等级的告警，直接返回橙色等级告警判定结果
                return result;
            }
            if (triggerAlarmLevel == QmsAlarmLevelEnum.NONE && StringUtils.isNotBlank(yellowAlarmValue)) {
                //判断黄色等级是否触发
                //如果触发了黄色等级的告警，直接返回黄色等级告警判定结果
                return result;
            }
            if (triggerAlarmLevel == QmsAlarmLevelEnum.NONE && StringUtils.isNotBlank(blueAlarmValue)) {
                //判断蓝色等级是否触发
                //如果触发了蓝色等级的告警，直接返回蓝色等级告警判定结果
                return result;
            }
            if (triggerAlarmLevel == QmsAlarmLevelEnum.NONE && triggerCancelAlarm == true) {
                //判断复归/平安是否触发，要求规则中设置的取消告警标记为true
                //如果触发了取消告警，直接返回取消告警判定结果
                return result;
            }
        }

        return result;
    }

    /**
     * 数据值不一致/不相等告警判定方法，需要提取相同点号不同时间的数据或者提取不同点号相同时间的数据
     *
     * @param pointid            点号编码
     * @param tmseg              点号时段类型
     * @param dataTime           数据时标
     * @param dataValue          数据值
     * @param errorProof         是否需要进行防误处理
     * @param valuefield         数据值字段
     * @param getDataConfig      判定提取数据配置
     * @param alarmContent       告警信息内容模板
     * @param redAlarmValue      红色告警值，可以为null，无效时不进行判定
     * @param orangeAlarmValue   橙色告警值，可以为null，无效时不进行判定
     * @param yellowAlarmValue   黄色告警值，可以为null，无效时不进行判定
     * @param blueAlarmValue     蓝色告警值，可以为null，无效时不进行判定
     * @param triggerCancelAlarm 是否触发取消/复归/平安报告警
     * @return qc.module.qms.dto.alarm.QmsPointDataValueAlarmRuleJudgeResultDto
     * @author QuCheng Tech
     * @since 2025/10/21
     */
    QmsPointDataValueAlarmRuleJudgeResultDto judgeValueNotEqualAlarm(String pointid, QmsPointTimeSegmentEnum tmseg, LocalDateTime dataTime, double dataValue, boolean errorProof,
                                                                     QmsPointValueFieldEnum valuefield, String getDataConfig, String alarmContent,
                                                                     String redAlarmValue, String orangeAlarmValue, String yellowAlarmValue, String blueAlarmValue, boolean triggerCancelAlarm) {
        //基本条件判断，如果输入不合理不触发任何告警；初始化判定结果为不触发任何告警
        QmsPointDataValueAlarmRuleJudgeResultDto result = new QmsPointDataValueAlarmRuleJudgeResultDto();
        result.setHasTriggerAlarm(false);
        result.setAlarmLevel(QmsAlarmLevelEnum.NONE);
        result.setHasTriggerErrorProof(false);
        result.setErrorProofRawDataValue(dataValue);
        result.setErrorProofSetDataValue(Double.NaN);

        //在告警方法未实现前，设置错误提示信息标识该告警判断方法未实现
        result.setErrorMsg("数据值不一致/不相等告警判定方法暂时未实现，不能进行告警判定");

        //如果本次的数据值为NaN或无穷大无法进行判定
        if (Double.isNaN(dataValue) == false && Double.isInfinite(dataValue) == false) {
            //记录逐个告警等级的判定结果，默认为不触发告警
            QmsAlarmLevelEnum triggerAlarmLevel = QmsAlarmLevelEnum.NONE;
            if (StringUtils.isNotBlank(redAlarmValue)) {
                //判断红色等级是否触发
                //如果触发了红色等级的告警，直接返回红色等级告警判定结果
                return result;
            }
            if (triggerAlarmLevel == QmsAlarmLevelEnum.NONE && StringUtils.isNotBlank(orangeAlarmValue)) {
                //判断橙色等级是否触发
                //如果触发了橙色等级的告警，直接返回橙色等级告警判定结果
                return result;
            }
            if (triggerAlarmLevel == QmsAlarmLevelEnum.NONE && StringUtils.isNotBlank(yellowAlarmValue)) {
                //判断黄色等级是否触发
                //如果触发了黄色等级的告警，直接返回黄色等级告警判定结果
                return result;
            }
            if (triggerAlarmLevel == QmsAlarmLevelEnum.NONE && StringUtils.isNotBlank(blueAlarmValue)) {
                //判断蓝色等级是否触发
                //如果触发了蓝色等级的告警，直接返回蓝色等级告警判定结果
                return result;
            }
            if (triggerAlarmLevel == QmsAlarmLevelEnum.NONE && triggerCancelAlarm == true) {
                //判断复归/平安是否触发，要求规则中设置的取消告警标记为true
                //如果触发了取消告警，直接返回取消告警判定结果
                return result;
            }
        }

        return result;
    }

    /**
     * 数据值全部相等（数据值长期不变）告警判定方法，需要提取同点号的时间往前的数据
     *
     * @param pointid            点号编码
     * @param tmseg              点号时段类型
     * @param dataTime           数据时标
     * @param dataValue          数据值
     * @param errorProof         是否需要进行防误处理
     * @param valuefield         数据值字段
     * @param getDataConfig      判定提取数据配置
     * @param alarmContent       告警信息内容模板
     * @param redAlarmValue      红色告警值，可以为null，无效时不进行判定
     * @param orangeAlarmValue   橙色告警值，可以为null，无效时不进行判定
     * @param yellowAlarmValue   黄色告警值，可以为null，无效时不进行判定
     * @param blueAlarmValue     蓝色告警值，可以为null，无效时不进行判定
     * @param triggerCancelAlarm 是否触发取消/复归/平安报告警
     * @return qc.module.qms.dto.alarm.QmsPointDataValueAlarmRuleJudgeResultDto
     * @author QuCheng Tech
     * @since 2025/10/21
     */
    QmsPointDataValueAlarmRuleJudgeResultDto judgeValueAllEqualAlarm(String pointid, QmsPointTimeSegmentEnum tmseg, LocalDateTime dataTime, double dataValue, boolean errorProof,
                                                                     QmsPointValueFieldEnum valuefield, String getDataConfig, String alarmContent,
                                                                     String redAlarmValue, String orangeAlarmValue, String yellowAlarmValue, String blueAlarmValue, boolean triggerCancelAlarm) {
        //基本条件判断，如果输入不合理不触发任何告警；初始化判定结果为不触发任何告警
        QmsPointDataValueAlarmRuleJudgeResultDto result = new QmsPointDataValueAlarmRuleJudgeResultDto();
        result.setHasTriggerAlarm(false);
        result.setAlarmLevel(QmsAlarmLevelEnum.NONE);
        result.setHasTriggerErrorProof(false);
        result.setErrorProofRawDataValue(dataValue);
        result.setErrorProofSetDataValue(Double.NaN);

        //在告警方法未实现前，设置错误提示信息标识该告警判断方法未实现
        result.setErrorMsg("数据值全部相等（数据值长期不变）告警判定方法暂时未实现，不能进行告警判定");

        //如果本次的数据值为NaN或无穷大无法进行判定
        if (Double.isNaN(dataValue) == false && Double.isInfinite(dataValue) == false) {
            //记录逐个告警等级的判定结果，默认为不触发告警
            QmsAlarmLevelEnum triggerAlarmLevel = QmsAlarmLevelEnum.NONE;
            if (StringUtils.isNotBlank(redAlarmValue)) {
                //判断红色等级是否触发
                //如果触发了红色等级的告警，直接返回红色等级告警判定结果
                return result;
            }
            if (triggerAlarmLevel == QmsAlarmLevelEnum.NONE && StringUtils.isNotBlank(orangeAlarmValue)) {
                //判断橙色等级是否触发
                //如果触发了橙色等级的告警，直接返回橙色等级告警判定结果
                return result;
            }
            if (triggerAlarmLevel == QmsAlarmLevelEnum.NONE && StringUtils.isNotBlank(yellowAlarmValue)) {
                //判断黄色等级是否触发
                //如果触发了黄色等级的告警，直接返回黄色等级告警判定结果
                return result;
            }
            if (triggerAlarmLevel == QmsAlarmLevelEnum.NONE && StringUtils.isNotBlank(blueAlarmValue)) {
                //判断蓝色等级是否触发
                //如果触发了蓝色等级的告警，直接返回蓝色等级告警判定结果
                return result;
            }
            if (triggerAlarmLevel == QmsAlarmLevelEnum.NONE && triggerCancelAlarm == true) {
                //判断复归/平安是否触发，要求规则中设置的取消告警标记为true
                //如果触发了取消告警，直接返回取消告警判定结果
                return result;
            }
        }

        return result;
    }

    /**
     * 数据值相加＞0，但乘积=0告警判定方法，需要提取同时间不同点号的数据
     * 使用场景：出力+发电量+发电流量＞0，且三者乘积＝0
     *
     * @param pointid            点号编码
     * @param tmseg              点号时段类型
     * @param dataTime           数据时标
     * @param dataValue          数据值
     * @param errorProof         是否需要进行防误处理
     * @param valuefield         数据值字段
     * @param getDataConfig      判定提取数据配置
     * @param alarmContent       告警信息内容模板
     * @param redAlarmValue      红色告警值，可以为null，无效时不进行判定
     * @param orangeAlarmValue   橙色告警值，可以为null，无效时不进行判定
     * @param yellowAlarmValue   黄色告警值，可以为null，无效时不进行判定
     * @param blueAlarmValue     蓝色告警值，可以为null，无效时不进行判定
     * @param triggerCancelAlarm 是否触发取消/复归/平安报告警
     * @return qc.module.qms.dto.alarm.QmsPointDataValueAlarmRuleJudgeResultDto
     * @author QuCheng Tech
     * @since 2025/10/21
     */
    QmsPointDataValueAlarmRuleJudgeResultDto judgeValueNonZeroAlarm(String pointid, QmsPointTimeSegmentEnum tmseg, LocalDateTime dataTime, double dataValue, boolean errorProof,
                                                                    QmsPointValueFieldEnum valuefield, String getDataConfig, String alarmContent,
                                                                    String redAlarmValue, String orangeAlarmValue, String yellowAlarmValue, String blueAlarmValue, boolean triggerCancelAlarm) {
        //基本条件判断，如果输入不合理不触发任何告警；初始化判定结果为不触发任何告警
        QmsPointDataValueAlarmRuleJudgeResultDto result = new QmsPointDataValueAlarmRuleJudgeResultDto();
        result.setHasTriggerAlarm(false);
        result.setAlarmLevel(QmsAlarmLevelEnum.NONE);
        result.setHasTriggerErrorProof(false);
        result.setErrorProofRawDataValue(dataValue);
        result.setErrorProofSetDataValue(Double.NaN);

        //在告警方法未实现前，设置错误提示信息标识该告警判断方法未实现
        result.setErrorMsg("数据值相加＞0，但乘积=0告警判定方法暂时未实现，不能进行告警判定");

        //如果本次的数据值为NaN或无穷大无法进行判定
        if (Double.isNaN(dataValue) == false && Double.isInfinite(dataValue) == false) {
            //记录逐个告警等级的判定结果，默认为不触发告警
            QmsAlarmLevelEnum triggerAlarmLevel = QmsAlarmLevelEnum.NONE;
            if (StringUtils.isNotBlank(redAlarmValue)) {
                //判断红色等级是否触发
                //如果触发了红色等级的告警，直接返回红色等级告警判定结果
                return result;
            }
            if (triggerAlarmLevel == QmsAlarmLevelEnum.NONE && StringUtils.isNotBlank(orangeAlarmValue)) {
                //判断橙色等级是否触发
                //如果触发了橙色等级的告警，直接返回橙色等级告警判定结果
                return result;
            }
            if (triggerAlarmLevel == QmsAlarmLevelEnum.NONE && StringUtils.isNotBlank(yellowAlarmValue)) {
                //判断黄色等级是否触发
                //如果触发了黄色等级的告警，直接返回黄色等级告警判定结果
                return result;
            }
            if (triggerAlarmLevel == QmsAlarmLevelEnum.NONE && StringUtils.isNotBlank(blueAlarmValue)) {
                //判断蓝色等级是否触发
                //如果触发了蓝色等级的告警，直接返回蓝色等级告警判定结果
                return result;
            }
            if (triggerAlarmLevel == QmsAlarmLevelEnum.NONE && triggerCancelAlarm == true) {
                //判断复归/平安是否触发，要求规则中设置的取消告警标记为true
                //如果触发了取消告警，直接返回取消告警判定结果
                return result;
            }
        }

        return result;
    }

    /**
     * 数据值变化趋势不一致告警判定方法，需要提取往前一段时间不同点号的数据
     * 使用场景：相邻小时出力变化量*相邻小时发电流量变化量＜告警阈值
     *
     * @param pointid            点号编码
     * @param tmseg              点号时段类型
     * @param dataTime           数据时标
     * @param dataValue          数据值
     * @param errorProof         是否需要进行防误处理
     * @param valuefield         数据值字段
     * @param getDataConfig      判定提取数据配置
     * @param alarmContent       告警信息内容模板
     * @param redAlarmValue      红色告警值，可以为null，无效时不进行判定
     * @param orangeAlarmValue   橙色告警值，可以为null，无效时不进行判定
     * @param yellowAlarmValue   黄色告警值，可以为null，无效时不进行判定
     * @param blueAlarmValue     蓝色告警值，可以为null，无效时不进行判定
     * @param triggerCancelAlarm 是否触发取消/复归/平安报告警
     * @return qc.module.qms.dto.alarm.QmsPointDataValueAlarmRuleJudgeResultDto
     * @author QuCheng Tech
     * @since 2025/10/21
     */
    QmsPointDataValueAlarmRuleJudgeResultDto judgeTrendencyNotSameAlarm(String pointid, QmsPointTimeSegmentEnum tmseg, LocalDateTime dataTime, double dataValue, boolean errorProof,
                                                                        QmsPointValueFieldEnum valuefield, String getDataConfig, String alarmContent,
                                                                        String redAlarmValue, String orangeAlarmValue, String yellowAlarmValue, String blueAlarmValue, boolean triggerCancelAlarm) {
        //基本条件判断，如果输入不合理不触发任何告警；初始化判定结果为不触发任何告警
        QmsPointDataValueAlarmRuleJudgeResultDto result = new QmsPointDataValueAlarmRuleJudgeResultDto();
        result.setHasTriggerAlarm(false);
        result.setAlarmLevel(QmsAlarmLevelEnum.NONE);
        result.setHasTriggerErrorProof(false);
        result.setErrorProofRawDataValue(dataValue);
        result.setErrorProofSetDataValue(Double.NaN);

        //在告警方法未实现前，设置错误提示信息标识该告警判断方法未实现
        result.setErrorMsg("数据值变化趋势不一致告警判定方法暂时未实现，不能进行告警判定");

        //如果本次的数据值为NaN或无穷大无法进行判定
        if (Double.isNaN(dataValue) == false && Double.isInfinite(dataValue) == false) {
            //记录逐个告警等级的判定结果，默认为不触发告警
            QmsAlarmLevelEnum triggerAlarmLevel = QmsAlarmLevelEnum.NONE;
            if (StringUtils.isNotBlank(redAlarmValue)) {
                //判断红色等级是否触发
                //如果触发了红色等级的告警，直接返回红色等级告警判定结果
                return result;
            }
            if (triggerAlarmLevel == QmsAlarmLevelEnum.NONE && StringUtils.isNotBlank(orangeAlarmValue)) {
                //判断橙色等级是否触发
                //如果触发了橙色等级的告警，直接返回橙色等级告警判定结果
                return result;
            }
            if (triggerAlarmLevel == QmsAlarmLevelEnum.NONE && StringUtils.isNotBlank(yellowAlarmValue)) {
                //判断黄色等级是否触发
                //如果触发了黄色等级的告警，直接返回黄色等级告警判定结果
                return result;
            }
            if (triggerAlarmLevel == QmsAlarmLevelEnum.NONE && StringUtils.isNotBlank(blueAlarmValue)) {
                //判断蓝色等级是否触发
                //如果触发了蓝色等级的告警，直接返回蓝色等级告警判定结果
                return result;
            }
            if (triggerAlarmLevel == QmsAlarmLevelEnum.NONE && triggerCancelAlarm == true) {
                //判断复归/平安是否触发，要求规则中设置的取消告警标记为true
                //如果触发了取消告警，直接返回取消告警判定结果
                return result;
            }
        }

        return result;
    }

    /**
     * 库水位数据不合理告警判定方法，需要提取往前一段时间相同点号的数据
     * 使用场景：相邻实时水位之差绝对值＞告警阈值且大于正常蓄水位（允许最高运行水位）
     * 使用场景：相邻实时水位之差绝对值＞告警阈值且＜死水位（允许最低运行水位）
     *
     * @param pointid            点号编码
     * @param tmseg              点号时段类型
     * @param dataTime           数据时标
     * @param dataValue          数据值
     * @param errorProof         是否需要进行防误处理
     * @param valuefield         数据值字段
     * @param getDataConfig      判定提取数据配置
     * @param alarmContent       告警信息内容模板
     * @param redAlarmValue      红色告警值，可以为null，无效时不进行判定
     * @param orangeAlarmValue   橙色告警值，可以为null，无效时不进行判定
     * @param yellowAlarmValue   黄色告警值，可以为null，无效时不进行判定
     * @param blueAlarmValue     蓝色告警值，可以为null，无效时不进行判定
     * @param triggerCancelAlarm 是否触发取消/复归/平安报告警
     * @return qc.module.qms.dto.alarm.QmsPointDataValueAlarmRuleJudgeResultDto
     * @author QuCheng Tech
     * @since 2025/10/21
     */
    QmsPointDataValueAlarmRuleJudgeResultDto judgeReservoirWaterErrorAlarm(String pointid, QmsPointTimeSegmentEnum tmseg, LocalDateTime dataTime, double dataValue, boolean errorProof,
                                                                           QmsPointValueFieldEnum valuefield, String getDataConfig, String alarmContent,
                                                                           String redAlarmValue, String orangeAlarmValue, String yellowAlarmValue, String blueAlarmValue, boolean triggerCancelAlarm) {
        //基本条件判断，如果输入不合理不触发任何告警；初始化判定结果为不触发任何告警
        QmsPointDataValueAlarmRuleJudgeResultDto result = new QmsPointDataValueAlarmRuleJudgeResultDto();
        result.setHasTriggerAlarm(false);
        result.setAlarmLevel(QmsAlarmLevelEnum.NONE);
        result.setHasTriggerErrorProof(false);
        result.setErrorProofRawDataValue(dataValue);
        result.setErrorProofSetDataValue(Double.NaN);

        //在告警方法未实现前，设置错误提示信息标识该告警判断方法未实现
        result.setErrorMsg("库水位数据不合理告警判定方法暂时未实现，不能进行告警判定");

        //如果本次的数据值为NaN或无穷大无法进行判定
        if (Double.isNaN(dataValue) == false && Double.isInfinite(dataValue) == false) {
            //记录逐个告警等级的判定结果，默认为不触发告警
            QmsAlarmLevelEnum triggerAlarmLevel = QmsAlarmLevelEnum.NONE;
            if (StringUtils.isNotBlank(redAlarmValue)) {
                //判断红色等级是否触发
                //如果触发了红色等级的告警，直接返回红色等级告警判定结果
                return result;
            }
            if (triggerAlarmLevel == QmsAlarmLevelEnum.NONE && StringUtils.isNotBlank(orangeAlarmValue)) {
                //判断橙色等级是否触发
                //如果触发了橙色等级的告警，直接返回橙色等级告警判定结果
                return result;
            }
            if (triggerAlarmLevel == QmsAlarmLevelEnum.NONE && StringUtils.isNotBlank(yellowAlarmValue)) {
                //判断黄色等级是否触发
                //如果触发了黄色等级的告警，直接返回黄色等级告警判定结果
                return result;
            }
            if (triggerAlarmLevel == QmsAlarmLevelEnum.NONE && StringUtils.isNotBlank(blueAlarmValue)) {
                //判断蓝色等级是否触发
                //如果触发了蓝色等级的告警，直接返回蓝色等级告警判定结果
                return result;
            }
            if (triggerAlarmLevel == QmsAlarmLevelEnum.NONE && triggerCancelAlarm == true) {
                //判断复归/平安是否触发，要求规则中设置的取消告警标记为true
                //如果触发了取消告警，直接返回取消告警判定结果
                return result;
            }
        }

        return result;
    }
}
